package com.huawei.admins.platform.gateway.core.component.filter.factory;

import com.huawei.admins.platform.gateway.core.component.filter.FilterDefinition;
import com.huawei.admins.platform.gateway.core.component.filter.GatewayFilter;
import com.huawei.admins.platform.gateway.core.component.filter.GatewayFilterChain;
import com.huawei.admins.platform.gateway.core.config.GatewayProperties;
import com.huawei.admins.platform.gateway.core.util.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.regex.Pattern;

import static com.huawei.admins.platform.gateway.core.util.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;

public class RewritePathGatewayFilterFactory extends AbstractGatewayFilterFactory<RewritePathGatewayFilterFactory.Config> {


    /**
     * Regexp key.
     */
    public static final String REGEXP_KEY = "regexp";

    /**
     * Replacement key.
     */
    public static final String REPLACEMENT_KEY = "replacement";

    public RewritePathGatewayFilterFactory(GatewayProperties properties) {
        super(properties);
    }

    @Override
    public GatewayFilter apply(String routeId, FilterDefinition definition) {

        Config config = loadConfiguration(routeId);
        String replacement = config.replacement.replace("$\\", "$");
        Pattern pattern = Pattern.compile(config.regexp);

        return new GatewayFilter() {

            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest req = exchange.getRequest();
                ServerWebExchangeUtils.addOriginalRequestUrl(exchange, req.getURI());

                String path = req.getURI().getRawPath();
                String newPath = pattern.matcher(path).replaceAll(replacement);

                ServerHttpRequest request = req.mutate().path(newPath).build();
                exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());

                return chain.filter(exchange.mutate().request(request).build());
            }

            @Override
            public String toString() {
                return RequestRateLimiterGatewayFilterFactory.class + ", " + config.getRegexp() + ", " + replacement;
            }

            @Override
            public int getOrder() {
                return 10;
            }
        };
    }

    @Override
    protected Config buildConfig(String routeId, Map<String, String> filterArgs) {
        String[] retryValues = filterArgs.values().toArray(new String[0]);
        if (retryValues.length != 2) {
            throw new IllegalArgumentException("No Configuration found for route " + routeId + " or defaultFilters");
        }
        return new Config().setRegexp(retryValues[0]).setReplacement(retryValues[1]);
    }

    public static class Config {

        private String regexp;

        private String replacement;

        public String getRegexp() {
            return regexp;
        }

        public Config setRegexp(String regexp) {
            Assert.hasText(regexp, "regexp must have a value");
            this.regexp = regexp;
            return this;
        }

        public String getReplacement() {
            return replacement;
        }

        public Config setReplacement(String replacement) {
            Assert.notNull(replacement, "replacement must not be null");
            this.replacement = replacement;
            return this;
        }

    }
}
